home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 7 / BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso / Files / Tele / C / Comet2.1.3.cpt / Comet / mactcp.c < prev    next >
Text File  |  1991-08-16  |  31KB  |  1,414 lines

  1. /* Copyright Cornell University 1986.  All rights are reserved. */
  2. /*  See permission and disclaimer notice in file "notice.h"  */
  3.  
  4. /* 10/6/89 kevin rewrote to use a circular buffer */
  5. /* 11/27/89 kevin tried to fix hang problem by checking emdp->connopen before read */
  6. /* 12/1/89 kevin modified so stream is released after every session */
  7.  
  8. #define     MACTCP
  9.  
  10. #include    <em.h>
  11.  
  12. #include    "tftp.h"
  13. #include    <menudefs.h>
  14. #include    <resdefs.h>
  15.  
  16. #include    <net.h>
  17.  
  18. #include    "mactcp.h"
  19.  
  20. #ifndef NULL
  21. #define NULL 0L
  22. #endif
  23.  
  24. #include <util.h>
  25.  
  26. char * ippname = "\P.IPP";            /* name of IP driver */
  27. short ipp_refnum;                    /* refnum of IP driver */
  28.  
  29. unsigned short maxseg = SENDBUFHIGH;            /* maximum segment size */
  30. short mactcpurgent;                    /* urgent flag */
  31.  
  32. TCPiopb statblk;                    /* statistics */
  33.  
  34. TCPiopb    tcp_read;                    /* Read control block */
  35. short read_req;
  36. short read_reread;
  37. short read_comp;
  38. short read_upcalled;
  39. short read_badreturns;
  40. short read_callfail;
  41. short read_fail;
  42.  
  43. struct rdsstruct {
  44.     rdsEntry rdstab[RDSSIZE];
  45.     unsigned short wdsend;    /* left zero to end RDS */
  46. } read_wds;
  47.  
  48. /* tcppb is an array of control blocks for sends */
  49.  
  50. struct tcppb {
  51.     TCPiopb        pb;                /* Mac parameter block for writes */
  52.     wdsEntry     wds1;                /* standard wds */
  53.     wdsEntry     wds2;                /* wds for use if buffer has wrapped */
  54.     short        wdsend;                /* always 0 */
  55.     struct winds * twp;                /* the sending window */
  56.     short        busy;                /* the pb is in use */
  57. }    tcppb[PBCOUNT];
  58.  
  59. short send_pend;                        /* # of sends pending completion */
  60. short send_next;                        /* index of next free PB */
  61. short send_req;
  62. short send_comp;
  63. short send_fail;
  64.  
  65. void mts_done();                /* send completion vector */
  66. void mtr_done();                /* read completion vector */
  67. void mtip_done();                /* ip init completion vector */
  68. void mtcl_done();                /* ip init completion vector */
  69. void mtopen_done();                /* ip init completion vector */
  70.  
  71. timer *tcp_tm;                /* timer for attempting resend if out of buffers */
  72. char readup;                /* an async read has been performed */
  73.  
  74. extern char *malloc();
  75. extern unsigned long getmyA5();
  76.  
  77. #define MTVALIDITY
  78. #define PROMPTSEND
  79.  
  80. #define ipctlGetAddr    15
  81.  
  82. /* MPW uses d0/d1/a0/a1 as scratch so we must preserve Aztec scratch regs 
  83.     just in case 
  84. */
  85.  
  86. #asm
  87. mpwcregs    reg    d0-d3/a0-a2
  88. #endasm
  89.  
  90. /* the TCP Async Notification Routine */
  91.  
  92. pascal void tcp_event(stream, eventCode, conp, terminReason, icmpMsg)
  93. StreamPtr stream;
  94. short eventCode;
  95. struct winds * conp;
  96. short terminReason;
  97. ICMPReport *icmpMsg;
  98. {
  99.     unsigned long oldA5;
  100.     
  101.     oldA5 = getmyA5(); 
  102.     
  103.     if (invalidconn(conp)) {
  104.         /* check to make sure the UserDataPtr points to a real window */
  105.         SysBeep(1);
  106.         if (keydp != NULL) {
  107.             prerrint25(keydp, "Received upcall from MacTCP for non-existent connection");
  108.         }
  109.         setA5(oldA5);
  110.         return;
  111.     }
  112.     
  113.     mtevent = TRUE;
  114.     switch (eventCode) {
  115.         case TCPClosing: {
  116.             if (!conp->closeflag)
  117.                 conp->closeflag = TRUE;
  118.             break;
  119.         }
  120.         case TCPULPTimeout: {
  121.             prerrint25(conp, "TCP Timeout");
  122.             break;
  123.         }
  124.         case TCPTerminate: {
  125.             if (conp->mtcpconnopen) {
  126.                 conp->closeflag = terminReason;
  127.                 conp->mtcpconnopen = FALSE;            /* connection no longer exists */
  128.                 if (!conp->closeflag) {
  129.                     conp->closeflag = TRUE;
  130.                 }
  131.             }
  132.             break;
  133.         }
  134.         case TCPDataArrival: {
  135.             conp->data_rcvd = TRUE;
  136.             break;
  137.         }
  138.         case TCPUrgent: {
  139.             break;
  140.         }
  141.         case TCPICMPReceived: {
  142.         /*
  143.             prerrint25(conp, "TCP ICMP Packet Received");
  144.         */
  145.             break;
  146.         }
  147.         default: {
  148.             prerrint25(conp, "Unknown TCP Notify Code received");
  149.             break;
  150.         }
  151.             
  152.     }
  153.     setA5(oldA5);
  154. }
  155.  
  156.  
  157. /* TODO these asynchronous routines are not reliable in MacTCP
  158.     as of 1.0.1.
  159.     
  160.     Multiple outstanding sends cause crashes on Mac+, so we
  161.     better not use 'em anyway.
  162.     
  163.     Async sends seem to cause problems on LocalTalk.
  164.     
  165.     Could be problems w/ MPW v C on args....
  166.     
  167.     OR could MacTCP be failing to save a1 (d1, d2) when making
  168.     direct trap calls after a GetTrapAddress?
  169.     
  170. */
  171.  
  172. void mtip_done(tcppb)
  173. TCPiopb *tcppb;
  174. {
  175.     unsigned long oldA5;
  176.     
  177.     oldA5 = getmyA5(); 
  178. #asm
  179.     movem.l    mpwcregs,-(a7)
  180. #endasm
  181.     
  182.     if (tcp_read.ioResult) {
  183.         ipp_refnum = tcp_read.ioCRefNum;
  184.         macipopen = TRUE;
  185.     }
  186. #asm
  187.     movem.l    (a7)+,mpwcregs
  188. #endasm
  189.     setA5(oldA5);
  190. }
  191.  
  192.  
  193. void mts_done(tcb)
  194. TCPiopb *tcb;
  195. {
  196.     wdsEntry *wds;
  197.     unsigned long oldA5;
  198.     struct tcppb * tcppbp;
  199.     
  200.     oldA5 = getmyA5(); 
  201. #asm
  202.     movem.l    mpwcregs,-(a7)
  203. #endasm
  204. #ifdef DYNAMICPB
  205.     tcppbp = (struct tcppb *) tcb->csParam.send.userDataPtr;
  206. #else
  207.     tcppbp = (struct tcppb *) tcb;
  208. #endif
  209.  
  210.     wds = (wdsEntry *) tcb->csParam.send.wdsPtr;
  211.     
  212.     if (tcb->ioResult) {
  213.         send_fail++;
  214.         /* prerrint25(twp, "send failure"); */
  215.     }
  216.     else {    
  217.         /* subtract the acked data from the count in the buffer */
  218.         tcppbp->twp->fillcount -= wds->length;
  219.         wds++;                                /* -> wds2 */
  220.         tcppbp->twp->fillcount -= wds->length;
  221.         
  222.         send_comp++;
  223.     }
  224.     --send_pend;
  225.     tcppbp->busy = FALSE;
  226. #asm
  227.     movem.l    (a7)+,mpwcregs
  228. #endasm
  229.     setA5(oldA5);
  230. }
  231.  
  232. #ifdef ASYNCCLOSE
  233.  
  234. void mtcl_done(tcppb)
  235. TCPiopb *tcppb;
  236. {
  237.     unsigned long oldA5;
  238.     struct winds * twp;
  239.  
  240.     oldA5 = getmyA5(); 
  241. #asm
  242.     movem.l    mpwcregs,-(a7)
  243. #endasm
  244.  
  245.     twp = (struct winds *) tcppb->csParam.send.userDataPtr;
  246.     twp->mtcpconnopen = FALSE;
  247.     
  248. #asm
  249.     movem.l    (a7)+,mpwcregs
  250. #endasm
  251.     setA5(oldA5);
  252. }
  253. #endif
  254.  
  255. #ifdef ASYNCOPEN
  256.  
  257. void mtopen_done(tcppb)
  258. TCPiopb *tcppb;
  259. {
  260.     unsigned long oldA5;
  261.     struct winds * twp;
  262.  
  263.     oldA5 = getmyA5(); 
  264. #asm
  265.     movem.l    mpwcregs,-(a7)
  266. #endasm
  267.  
  268.     twp = (struct winds *) tcppb->csParam.send.userDataPtr;
  269.     
  270.     if (tcppb->ioResult == openFailed) {
  271.         tcp_err(tcppb->ioResult);
  272.         twp->closeflag = -2;
  273.         return(1);
  274.     }
  275.     else if (tcppb->ioResult) {
  276.         tcp_err(tcppb->ioResult);
  277.         twp->closeflag = -2;
  278.         return(1);
  279.     }
  280.     twp->openflag = TRUE;
  281.     twp->mtcpconnopen = TRUE;
  282.     mtevent = TRUE;
  283.     /* opn_usr() will be called asynchronously */
  284. #asm
  285.     movem.l    (a7)+,mpwcregs
  286. #endasm
  287.     setA5(oldA5);
  288. }
  289.  
  290. #endif
  291.  
  292. tcp_upcall()
  293. {
  294.     short index;
  295.     OSErr errcode;
  296.     
  297.     readup = FALSE;
  298.     emdp->data_rcvd = FALSE;
  299.  
  300.     tcp_read.tcpStream = emdp->tcp_stream;
  301.     
  302.     tcp_read.csCode = TCPNoCopyRcv;
  303.     PBControl(&tcp_read, (Boolean) FALSE);
  304.  
  305.     if (tcp_read.ioResult) {
  306.         read_fail++;
  307.         if (emdp->mtcpconnopen) {
  308.             /* ASYNC read always fails once connection broken */
  309.             tcp_err(tcp_read.ioResult);
  310.         }
  311.     }
  312.     else {
  313.  
  314.         for (index = 0; read_wds.rdstab[index].length; index++) {
  315.             wr_usr(read_wds.rdstab[index].ptr, read_wds.rdstab[index].length);
  316.         }            
  317.         read_upcalled++;
  318.     }
  319.     /* free the buffers we read */
  320.     tcp_read.csCode = TCPRcvBfrReturn;
  321.     if (errcode = PBControl(&tcp_read, (Boolean) FALSE)) {
  322.         read_badreturns++;
  323.     }
  324. }
  325.  
  326.  
  327. /* SHOULD open the Internet Packet driver asynchronously 
  328.     so we can do other stuff BUT doesn't seem to call completion! */
  329.  
  330. ParamBlkRec openblk;
  331.  
  332. macip_init()
  333. {
  334.     /* use the openblk block to save some space */
  335.     TCPiopb infoblk;
  336.     
  337.     if (macipopen)
  338.         return(0);
  339.         
  340.     openblk.ioNamePtr = (StringPtr) ippname;
  341.     openblk.u.iop.ioPermssn = 0;                /* ioPermssn field */
  342.         /* fsRdWrPerm seems to cause crash...*/
  343.         
  344. #ifdef IPASYNC
  345.     openblk.ioCompletion = mtip_done;
  346.     PBOpen(&openblk, (Boolean) TRUE);
  347. #else
  348. #ifdef OPENDRIVER
  349.     if (OpenDriver(ippname, &ipp_refnum)) {
  350.         error("Can't open MacTCP; check MacTCP configuration for correct net #, gateway address, and unique node address");
  351.         return(-1);
  352.     }
  353. #else
  354.     openblk.ioCompletion = NULL;
  355.     PBOpen(&openblk, (Boolean) FALSE);
  356.     if (openblk.ioResult) {
  357.         error("Can't open MacTCP; check MacTCP configuration for correct net #, gateway address, and unique node address");
  358.         return(-1);
  359.     }
  360.     ipp_refnum = openblk.u.iop.ioRefNum;
  361. #endif
  362.     macipopen = TRUE;
  363.  
  364.     /* get our IP address */
  365.     memzero(&infoblk, sizeof(struct TCPiopb));    
  366.  
  367.     infoblk.ioCRefNum = ipp_refnum;
  368.     infoblk.csCode = ipctlGetAddr;
  369.     PBControl(&infoblk, (Boolean) FALSE);
  370.     if (infoblk.ioResult) {
  371.         rnet->ip_addr = 0;
  372.     }
  373.     else
  374.         rnet->ip_addr = infoblk.tcpStream;    
  375.         /* kluge to avoid defining GetMyIPAddr pb */
  376.  
  377. #endif
  378.     return(0);
  379. }
  380.  
  381.  
  382. mactcp_init()
  383. {
  384.     short cnt;
  385.     TCPiopb infoblk;
  386.  
  387.     if (mactcpopen)
  388.         return(0);
  389.         
  390.     if (!macipopen) {
  391.         if (macip_init()) {
  392.             return(-1);
  393.         }
  394.     }
  395.  
  396.     memzero(&infoblk, sizeof(struct TCPiopb));    
  397.  
  398.     /* allocate resend retry timer */
  399.     if (tcp_tm == NULL) {
  400.         /* first time through */
  401.         if ((tcp_tm = tm_alloc()) == NULL)
  402.             return(-1);
  403.     }
  404.  
  405. #ifdef IPASYNC
  406.     while (openblk.ioResult == 1)
  407.         ;
  408.         
  409.     /* wait for async IP init to complete */
  410.     if (openblk.ioResult) {
  411.         error("Can't open MacTCP driver");
  412.         return(-1);
  413.     }
  414.     ipp_refnum = openblk.ioCRefNum;
  415. #endif
  416.  
  417.     tcp_read.ioNamePtr = (StringPtr) NULL;
  418.     infoblk.ioCRefNum = ipp_refnum;
  419.     infoblk.csCode = TCPGlobalInfo;
  420.  
  421.     /* get MSS.  NB: MacTCP hangs if send WDS is > MSS!!!!! */
  422.     
  423.     if (PBControl(&infoblk, (Boolean) FALSE)) {
  424.         error("Can't get MacTCP MSS, using 512 default");
  425.     }
  426.     else 
  427.         maxseg = infoblk.csParam.globalInfo.tcpParamPtr->tcpMaxSegSize;
  428.  
  429.     /* set up read PB */
  430.     tcp_read.ioCRefNum = ipp_refnum;
  431.     tcp_read.csCode = TCPNoCopyRcv;
  432.     tcp_read.csParam.receive.rdsPtr = (Ptr) &read_wds;
  433.     tcp_read.csParam.receive.rdsLength = RDSSIZE;
  434.     tcp_read.ioCompletion = NULL;
  435.     tcp_read.csParam.receive.commandTimeoutValue = 1;
  436.  
  437.     /* allocate send pbs */
  438.     for (cnt = 0; cnt < PBCOUNT; cnt++) {
  439. #ifdef DYNAMICPB
  440.         tcppb[cnt].pb = (TCPiopb *) malloc(sizeof(struct TCPiopb));
  441.         if (tcppb[cnt].pb == NULL) {
  442.             return(-1);
  443.         }
  444.         tcppb[cnt].pb = StripAddress(tcppb[cnt].pb);
  445.         memzero(tcppb[cnt].pb, sizeof(struct TCPiopb));
  446. #endif
  447.  
  448.         tcppb[cnt].pb.csCode = TCPSend;
  449.         tcppb[cnt].pb.ioCRefNum = ipp_refnum;
  450.         tcppb[cnt].pb.ioCompletion = NULL;
  451. #ifdef MTVALIDITY
  452.         /* set timeout value */
  453.         tcppb[cnt].pb.csParam.send.ulpTimeoutValue = 255;
  454.         tcppb[cnt].pb.csParam.send.ulpTimeoutAction = 1;    /* was 1, abort */
  455.         tcppb[cnt].pb.csParam.send.validityFlags = timeoutValue | timeoutAction;
  456. #endif
  457.  
  458.         tcppb[cnt].pb.csParam.send.pushFlag = TRUE;
  459.         tcppb[cnt].pb.csParam.send.wdsPtr = (Ptr) &tcppb[cnt].wds1;
  460.         
  461.         /* setup wds for this PB */
  462.         tcppb[cnt].wdsend = 0;
  463.     }
  464.     mactcpopen = TRUE;
  465.  
  466.     return(0);
  467. }
  468.  
  469. /* call macTCP to make a stream */
  470.  
  471. tcp_makestream()
  472. {
  473.     /* TCPiopb tblk;
  474.         TODO could the allocation of the stream on the stack rather than
  475.             permanently be causing problems? probably not ...*/
  476.  
  477.     if (emdp->tcp_stream)
  478.         /* we already have a stream allocated */
  479.         return(0);
  480.         
  481.     if (emdp->mtstream == NULL) {
  482.         /* allocate TCP stream create memory; may not be necessary to save this... */
  483.         if ((emdp->mtstream = (char *) malloc(sizeof(struct TCPiopb))) == NULL) {
  484.             tcpmemoryreclaim(emdp);
  485.             return(-1);
  486.         }
  487.         emdp->mtstream = StripAddress(emdp->mtstream);
  488.     
  489.         /* allocate send buffer */
  490.         emdp->sendbuf = (unsigned char *) malloc(SENDBUFSIZE);
  491.         if (emdp->sendbuf == NULL) {
  492.             tcpmemoryreclaim(emdp);
  493.             return(-1);
  494.         }
  495.         emdp->sendbuf = StripAddress(emdp->sendbuf);
  496.         
  497.         /* allocate connection block */
  498.         emdp->tcp_conn = (TCPiopb *) malloc(sizeof(TCPiopb));
  499.         if (emdp->tcp_conn == NULL) {
  500.             tcpmemoryreclaim(emdp);
  501.             return(-1);
  502.         }
  503.         emdp->tcp_conn = StripAddress(emdp->tcp_conn);
  504.     
  505.         /* allocate the receive buffer */
  506.         if ((emdp->rcvbuf = (char *) malloc(BUFLEN)) == NULL) {
  507.             tcpmemoryreclaim(emdp);
  508.             return(-1);
  509.         }
  510.         emdp->rcvbuf = StripAddress(emdp->rcvbuf);
  511.     }
  512.     /* initialize the elements... */
  513.     
  514.     memzero(emdp->mtstream, sizeof(struct TCPiopb));    
  515.     emdp->sendp = emdp->fillp = emdp->sendbuf;
  516.     emdp->fillendp = emdp->sendbuf + SENDBUFSIZE;
  517.     memzero(emdp->tcp_conn, sizeof(struct TCPiopb));    
  518.     
  519.     emdp->mtstream->ioCRefNum = ipp_refnum;
  520.     emdp->mtstream->csCode = TCPCreate;
  521.     emdp->mtstream->csParam.create.rcvBuff = emdp->rcvbuf;
  522.     emdp->mtstream->csParam.create.rcvBuffLen = (unsigned long) BUFLEN;
  523.     emdp->mtstream->csParam.create.notifyProc = (ProcPtr) tcp_event;
  524.     emdp->mtstream->csParam.create.userDataPtr = emdp;
  525.     PBControl(emdp->mtstream, (Boolean) FALSE);
  526.     if (emdp->mtstream->ioResult) {
  527.         tcp_err(emdp->mtstream->ioResult);
  528.         tcpmemoryreclaim(emdp);
  529.         return(-1);
  530.     }
  531.     
  532.     /* we get the stream * in return */
  533.     emdp->tcp_stream = emdp->mtstream->tcpStream;
  534.         /* if we don't do this assignment, it doesn't work... ??? */
  535.     emdp->tcp_stream = StripAddress(emdp->tcp_stream);
  536.  
  537.     return(0);
  538. }
  539.  
  540. /* add a character to the send buffer */
  541.  
  542. mactcp_put(thechar)
  543. char thechar;
  544. {
  545.     if (!emdp->mtcpconnopen)
  546.         return(-1);
  547.         
  548.     if (emdp->fillcount >= SENDBUFSIZE) {
  549.         return(-1);
  550.     }
  551.  
  552.     /* stick the character in the buffer */
  553.     emdp->fillcount++;
  554.     emdp->waitcount++;
  555.     *emdp->fillp++ = thechar;
  556.     if (emdp->fillp >= emdp->fillendp) {
  557.         /* wrap around if we're at the end of the buffer */
  558.         emdp->fillp = emdp->sendbuf;
  559.     }
  560.  
  561. #ifdef PROMPTSEND    
  562.     if (emdp->waitcount >= maxseg)
  563.         /* send if the buffer gets full */
  564.         mactcp_ex();
  565. #endif
  566.  
  567.     return(0);
  568. }
  569.  
  570.  
  571. /* add a character to the buffer and send the packet promptly */
  572.  
  573. mactcp_fput(thechar)
  574. char thechar;
  575. {
  576.     if (!emdp->mtcpconnopen)
  577.         return(-1);
  578.         
  579.     if (! (emdp->fillcount < SENDBUFSIZE)) {
  580.         return(-1);
  581.     }
  582.  
  583.     /* stick the character in the buffer */
  584.     emdp->fillcount++;
  585.     emdp->waitcount++;
  586.     *emdp->fillp++ = thechar;
  587.     if (emdp->fillp >= emdp->fillendp) {
  588.         /* wrap around if we're at the end of the buffer */
  589.         emdp->fillp = emdp->sendbuf;
  590.     }
  591.  
  592.     mactcp_ex();
  593.     return(0);
  594. }
  595.  
  596.  
  597. /* the better to trap retries for PB available */
  598.  
  599. tcp_rex() 
  600. {
  601.     mactcp_ex();
  602. }
  603.  
  604.  
  605. /* send outstanding data  */
  606.  
  607. mactcp_ex() 
  608. {
  609.     unsigned short sendcount;
  610.     unsigned short send2;
  611.  
  612.     if (!emdp->mtcpconnopen)
  613.         return(-1);
  614.         
  615.     if (emdp->waitcount == 0) {
  616.         /* nothing to send */
  617.         emdp->send_wait = FALSE;
  618.         return(0);
  619.     }
  620.     else {
  621.         emdp->send_wait = TRUE;
  622.         mtevent = TRUE;                    /* guarantee we get service */
  623.     }
  624.  
  625.     if (send_pend >= PBCOUNT) {
  626.         /* we don't have a free parameter block, reschedule */
  627. #ifdef TCP_REX
  628.         tm_tset(1, tcp_rex, emdp, tcp_tm);
  629. #endif
  630.         return(-2);
  631.     }
  632.     if (tcppb[send_next].busy) {
  633.         /* find a free pb */
  634.         int sendindex;
  635.         
  636.         for (sendindex = send_next + 1; sendindex < PBCOUNT; sendindex++) {
  637.             if (tcppb[sendindex].busy)
  638.                 continue;
  639.         }
  640.         if (sendindex == PBCOUNT) {
  641.             /* didn't find one yet, wrap around */
  642.             for (sendindex = 0; sendindex < send_next; sendindex++) {
  643.                 if (tcppb[sendindex].busy)
  644.                     continue;
  645.             }
  646.             if (sendindex == send_next) {
  647.                 /* no free pb, shouldn't happen here since PBCOUNT tested */
  648.                 /* TODO--make a new send buffer? */
  649.                 return(-3);
  650.             }
  651.         }
  652.         send_next = sendindex;
  653.     }
  654.     if (emdp->fillp < emdp->sendp)
  655.         /* data has wrapped */
  656.         sendcount = emdp->fillendp - emdp->sendp;
  657.     else
  658.         sendcount = emdp->fillp - emdp->sendp;
  659.  
  660. #ifdef PROMPTSEND    
  661.     if (sendcount > maxseg) {
  662.         /* MacTCP chokes if a segment is > MSS ... */
  663.         sendcount = maxseg;
  664.     }
  665. #endif
  666.  
  667.     /* per window in send */
  668.     tcppb[send_next].twp = emdp;
  669.  
  670. #ifdef DYNAMICPB
  671.     tcppb[send_next].pb.csParam.send.userDataPtr = &tcppb[send_next];
  672. #else
  673.     tcppb[send_next].pb.csParam.send.userDataPtr = emdp;
  674. #endif
  675.     tcppb[send_next].pb.csParam.send.urgentFlag = mactcpurgent;
  676.  
  677.     tcppb[send_next].pb.tcpStream = emdp->tcp_stream;
  678.  
  679.     tcppb[send_next].wds1.ptr = emdp->sendp;
  680.     tcppb[send_next].wds1.length = sendcount;
  681.  
  682. #ifdef TCPBUFWRAP
  683.     if (emdp->fillp < emdp->sendp && sendcount < maxseg) {
  684.         /* data wrapped, we can use two elements in the WDS */
  685.         /* we can send some of the wrapped data */
  686.         /* HOWEVER this is no win, since MacTCP sends two pkts anyway */
  687.         
  688.         send2 = emdp->fillp - emdp->sendbuf;
  689.         if ((sendcount + send2) >= maxseg) {
  690.             send2 = maxseg - sendcount;
  691.             sendcount = maxseg;
  692.         }
  693.         else {
  694.             sendcount += send2;
  695.         }
  696.         tcppb[send_next].wds2.length = send2;
  697.         tcppb[send_next].wds2.ptr = emdp->sendbuf;
  698.         tcppb[send_next].wdsend = 0;                    /* terminate WDS2 */
  699.     }
  700.     else {
  701.         tcppb[send_next].wds2.length = 0;                /* terminate WDS1 */
  702.         tcppb[send_next].wds2.ptr = NULL;
  703.     }
  704. #else
  705.     tcppb[send_next].wds2.length = 0;                    /* terminate WDS1 */
  706.     tcppb[send_next].wds2.ptr = NULL;
  707. #endif
  708.  
  709.     send_req++;
  710.     if (mtcpsendasync) {
  711.         /* if user is configured for async send, do so... */
  712.         tcppb[send_next].pb.ioCompletion = mts_done;
  713.         tcppb[send_next].busy = TRUE;
  714.         if (PBControl(&tcppb[send_next].pb, (Boolean) TRUE)) {
  715.             /* TODO retries?  just bomb out? */
  716.             send_fail++;
  717.             tcppb[send_next].busy = FALSE;
  718.             tcp_err(tcppb[send_next].pb.ioResult);
  719.             return(-1);
  720.         }
  721.         send_pend++;
  722.         if (++send_next >= PBCOUNT)
  723.             send_next = 0;
  724.     }
  725.     else {
  726.         /* use the synchronous call, which is a bummer because
  727.             it does not return until after the data is acked... */
  728.         if (tcppb[send_next].pb.ioCompletion) {
  729.             /* who the fuck is tampering with this? */
  730.             beartrap();
  731.             tcppb[send_next].pb.ioCompletion = NULL;
  732.         }
  733.             
  734.         if (PBControl(&tcppb[send_next].pb, (Boolean) FALSE)) {
  735.             /* TODO retries?  just bomb out? */
  736.             send_fail++;
  737.             tcp_err(tcppb[send_next].pb.ioResult);
  738.             return(-1);
  739.         }
  740.         if (tcppb[send_next].pb.ioCompletion) {
  741.             /* who the fuck is tampering with this? */
  742.             beartrap();
  743.             tcppb[send_next].pb.ioCompletion = NULL;
  744.         }
  745.         /* subtract the acked data from the count in the buffer */
  746.         emdp->fillcount -= sendcount;
  747.         send_comp++;
  748.     }
  749.     emdp->waitcount -= sendcount;
  750.  
  751.     /* set emdp->sendp -> next char needing send */
  752.     emdp->sendp += sendcount;
  753.     if (emdp->sendp >= emdp->fillendp) {
  754.         /* wrap pointer if necessary */
  755.         emdp->sendp -= SENDBUFSIZE;
  756.     }
  757.     
  758.     return(0);
  759. }
  760.  
  761.  
  762. /* open a connection with a host */
  763.  
  764. mactcp_open(addr, port)
  765. long * addr;
  766. short port;
  767. /* a short local socket argument is also a parameter, not used w/ mactcp */
  768. {
  769.     if (!mactcpopen) {
  770.         if (mactcp_init()) {
  771.             return(-1);
  772.         }
  773.     }
  774.     if (tcp_makestream())
  775.         return(-1);
  776.  
  777.     emdp->tcp_conn->ioCRefNum = ipp_refnum;
  778.     emdp->tcp_conn->csCode = TCPActiveOpen;
  779.     emdp->tcp_conn->tcpStream = emdp->tcp_stream;
  780. #ifdef MTVALIDITY
  781.     emdp->tcp_conn->csParam.open.ulpTimeoutValue = 15;    /* was 15 */
  782.     emdp->tcp_conn->csParam.open.ulpTimeoutAction = 1;    /* abort 1, report 0 */
  783.     emdp->tcp_conn->csParam.open.validityFlags = timeoutValue | timeoutAction; 
  784. #endif
  785.     emdp->tcp_conn->csParam.open.remoteHost = *addr;
  786.     emdp->tcp_conn->csParam.open.remotePort = port;
  787.     emdp->tcp_conn->csParam.open.localPort = 0;                /* let mactcp assign */
  788.     emdp->tcp_conn->csParam.open.dontFrag = 1;
  789.     emdp->tcp_conn->csParam.open.timeToLive = 0;                /* let mactcp assign */
  790.     emdp->tcp_conn->csParam.open.security = 0;                /* let mactcp assign */
  791.     emdp->tcp_conn->csParam.open.optionCnt = 0;                /* no IP options */
  792.         /* commandTimeoutValue not used as per manual */
  793.  
  794.     emdp->tcp_conn->csParam.open.userDataPtr = emdp;
  795. #ifdef ASYNCOPEN
  796.     emdp->tcp_conn->ioCompletion = mtopen_done;
  797.  
  798.     PBControl(emdp->tcp_conn, (Boolean) TRUE);
  799. #else
  800.     emdp->tcp_conn->ioCompletion = NULL;
  801.     
  802.     SetCursor(*GetCursor(watchCursor));
  803.         /* put up a watch cursor to show this may take some time */
  804.         
  805.     PBControl(emdp->tcp_conn, (Boolean) FALSE);
  806.     
  807.     SetCursor(&arrow);
  808.     
  809.     if (emdp->tcp_conn->ioResult == openFailed) {
  810.         tcp_err(emdp->tcp_conn->ioResult);
  811.         emdp->closeflag = -2;
  812.         return(1);
  813.     }
  814.     else if (emdp->tcp_conn->ioResult) {
  815.         tcp_err(emdp->tcp_conn->ioResult);
  816.         emdp->closeflag = -2;
  817.         return(1);
  818.     }
  819.     emdp->mtcpconnopen = TRUE;
  820.     opn_usr();        /* this comes after completion if async call */
  821. #endif
  822.     return(0);
  823. }
  824.  
  825.  
  826.  
  827. /* stubs
  828.  
  829. needs to be implemented for mactcp
  830.  
  831. IcEchoRequest()
  832. {
  833. }
  834.  
  835.  */
  836.  
  837. mactcp_close()
  838. {
  839.     TCPiopb closePB;
  840.     
  841.     if (!emdp->mtcpconnopen || !emdp->tcp_stream)
  842.         return(-1);
  843.         
  844.     /* PBControl(&statblk, (Boolean) FALSE));        get pre-closing status */
  845.  
  846.     memzero(&closePB, sizeof(struct TCPiopb));    
  847.  
  848.     closePB.ioCRefNum = ipp_refnum;
  849.     closePB.csCode = TCPClose;
  850.     closePB.tcpStream = emdp->tcp_stream;
  851.     closePB.csParam.close.userDataPtr = emdp;
  852. #ifdef MTVALIDITY
  853.     closePB.csParam.close.ulpTimeoutValue = 30;        /* was 30 */
  854.     closePB.csParam.close.ulpTimeoutAction = 1;        /* abort, zero = report */
  855.     closePB.csParam.close.validityFlags = timeoutValue | timeoutAction; 
  856. #endif
  857.  
  858. #ifdef ASYNCCLOSE
  859.     closePB.ioCompletion = mtcl_done;
  860.     if (PBControl(&closePB, (Boolean) TRUE)) {
  861.         prerrint25(emdp, "TCP Close call failed");
  862.     }
  863. #else
  864.     closePB.ioCompletion = NULL;
  865.     if (PBControl(&closePB, (Boolean) FALSE)) {
  866.         prerrint25(emdp, "TCP Close call failed");
  867.         /* make sure user can quit application anyway... */
  868.         emdp->mtcpconnopen = FALSE;            /* connection no longer exists */
  869.         emdp->closeflag = TRUE;
  870.     }
  871.     else {
  872.         emdp->mtcpconnopen = FALSE;
  873.         /* statblk.csParam.status.connectionState = CLOSED;    fix stat report */
  874.     }
  875. #endif
  876.     return(0);
  877. }
  878.  
  879.  
  880.  
  881. /* release a stream */
  882.  
  883. tcp_release(twp)
  884. struct winds * twp;
  885. {
  886.     TCPiopb relPB;
  887.     
  888.     if (!twp->tcp_stream)
  889.         return(-1);
  890.         
  891.     memzero(&relPB, sizeof(struct TCPiopb));    
  892.  
  893.     relPB.ioCRefNum = ipp_refnum;
  894.     relPB.csCode = TCPRelease;
  895.     relPB.tcpStream = twp->tcp_stream;
  896.     relPB.csParam.release.userDataPtr = twp;
  897.  
  898.     if (PBControl(&relPB, (Boolean) FALSE)) {
  899.         error("MacTCP stream release failed");
  900.         return(-1);
  901.     }
  902.     twp->tcp_stream = 0;
  903.     twp->mtcpconnopen = FALSE;
  904.     return(0);
  905. }
  906.  
  907.  
  908. /* abort a connection not used? */
  909.  
  910. mactcpclrsendbuf()
  911. {
  912.     TCPiopb abortPB;
  913.     
  914.     if (!emdp->mtcpconnopen)
  915.         return(-1);
  916.         
  917.     memzero(&abortPB, sizeof(struct TCPiopb));    
  918.  
  919.     abortPB.ioCRefNum = ipp_refnum;
  920.     abortPB.csCode = TCPAbort;
  921.     abortPB.tcpStream = emdp->tcp_stream;
  922.     abortPB.csParam.abort.userDataPtr = emdp;
  923.  
  924.     if (PBControl(&abortPB, (Boolean) FALSE)) {
  925.         error("session abort failed");
  926.         return(-1);
  927.     }
  928.     /* mactcp_wrapup(); */
  929.     emdp->mtcpconnopen = FALSE;
  930.     emdp->closeflag = TRUE;
  931.     return(0);
  932. }
  933.  
  934.  
  935. /* works only in emdp context */
  936.  
  937. tcp_err(errcode)
  938. OSErr errcode;
  939. {
  940.     switch (errcode) {
  941.         case inProgress:
  942.             prerrint25(emdp, "I/O in progress");
  943.             break;
  944.         case ipBadLapErr:
  945.             prerrint25(emdp, "bad network configuration");
  946.             break;
  947.         case ipBadCnfgErr:
  948.             prerrint25(emdp, "bad IP configuration error");
  949.             break;
  950.         case ipNoCnfgErr:
  951.             prerrint25(emdp, "missing IP or LAP configuration error");
  952.             break;
  953.         case ipLoadErr:
  954.             prerrint25(emdp, "error in MacTCP load");
  955.             break;
  956.         case ipBadAddr:
  957.             prerrint25(emdp, "error in getting address");
  958.             break;
  959.         case connectionClosing:
  960.             prerrint25(emdp, "connection is closing");
  961.             break;
  962.         case invalidLength:
  963.             prerrint25(emdp, "invalid length");
  964.             break;
  965.         case connectionExists:
  966.             prerrint25(emdp, "request conflicts with existing connection");
  967.             break;
  968.         case connectionDoesntExist:
  969.             prerrint25(emdp, "connection does not exist");
  970.             break;
  971.         case insufficientResources:
  972.             prerrint25(emdp, "insufficient resources to perform request");
  973.             break;
  974.         case invalidStreamPtr:
  975.             prerrint25(emdp, "invalid stream ptr");
  976.             break;
  977.         case streamAlreadyOpen:
  978.             prerrint25(emdp, "stream already open");
  979.             break;
  980.         case connectionTerminated:
  981.             prerrint25(emdp, "connection terminated");
  982.             break;
  983.         case invalidBufPtr:
  984.             prerrint25(emdp, "invalid buffer ptr");
  985.             break;
  986.         case invalidWDS:
  987.             prerrint25(emdp, "invalid WDS");
  988.             /* also covers RDS */
  989.             break;
  990.         case openFailed:
  991.             prerrint25(emdp, "Session closed:  Can't connect to host");
  992.             break;
  993.         case commandTimeout:
  994.             prerrint25(emdp, "command timed out");
  995.             break;
  996.         case duplicateSocket:
  997.             prerrint25(emdp, "duplicate socket");
  998.             break;
  999.  
  1000. /* Error codes from internal IP functions */
  1001.         case ipDontFragErr:
  1002.             prerrint25(emdp, "Packet too large to send w/o fragmenting");
  1003.             break;
  1004.         case ipDestDeadErr:
  1005.             prerrint25(emdp, "destination not responding");
  1006.             break;
  1007.         case ipNoFragMemErr:
  1008.             prerrint25(emdp, "no memory to send fragmented pkt");
  1009.             break;
  1010.         case ipRouteErr:
  1011.             prerrint25(emdp, "can't route packet off-net");
  1012.             break;
  1013.  
  1014.         case outOfMemory:
  1015.             prerrint25(emdp, "Out of memory");
  1016.             break;
  1017.         default:
  1018.             prerrint25(emdp, "Unknown TCP error");
  1019.             break;
  1020.     }
  1021. }
  1022.  
  1023.  
  1024. char * mtcptermarr[] = {
  1025.     "",
  1026.     "",
  1027.     "Session closed:  Host has abruptly closed session with a Reset",
  1028.     "Session closed:  Network failure",
  1029.     "Session closed:  Security/precedence mismatch",
  1030.     "Session closed:  a timeout has occurred",
  1031.     "Session closed:  an abort has occurred",
  1032.     "Session closed",
  1033.     "Session closed:  Service failure"
  1034. };
  1035.  
  1036.  
  1037. term_report(cause)
  1038. short cause;
  1039. {
  1040.     int sessionkilled = FALSE;
  1041.     
  1042.     switch (cause) {
  1043.         case -2: {
  1044.             /* our tag for failure to connect */
  1045.             sessionkilled = TRUE;
  1046.             break;
  1047.         }
  1048.         case 2: {
  1049.             prerrint25(emdp, mtcptermarr[cause]);
  1050.             sessionkilled = TRUE;
  1051.             break;
  1052.         }
  1053.         case 3: {
  1054.             prerrint25(emdp, mtcptermarr[cause]);
  1055.             sessionkilled = TRUE;
  1056.             break;
  1057.         }
  1058.         case 4: {
  1059.             prerrint25(emdp, mtcptermarr[cause]);
  1060.             sessionkilled = TRUE;
  1061.             break;
  1062.         }
  1063.         case 5: {
  1064.             prerrint25(emdp, mtcptermarr[cause]);
  1065.             sessionkilled = TRUE;
  1066.             break;
  1067.         }
  1068.         case 6: {
  1069.             prerrint25(emdp, mtcptermarr[cause]);
  1070.             sessionkilled = TRUE;
  1071.             break;
  1072.         }
  1073.         case 7: {
  1074.             /* this is a normal close requested from the user layer */
  1075.             prerrint25(emdp, mtcptermarr[cause]);
  1076.             break;
  1077.         }
  1078.         case 8: {
  1079.             prerrint25(emdp, mtcptermarr[cause]);
  1080.             sessionkilled = TRUE;
  1081.             break;
  1082.         }
  1083.     }
  1084.     if (sessionkilled) {
  1085.         /* alert used session died abnormally */
  1086.         beep();
  1087.         windmenumark(emdp, 0xA0);            /* set a † mark */
  1088.     }
  1089.     else
  1090.         windmenumark(emdp, noMark);        /* clear any marks */
  1091. }
  1092.  
  1093.  
  1094. /* wrap up a MacTCP connection, close if necessary, reset UI */
  1095. /* WARNING: twp may disappear & emdp change when this function is called! */
  1096.             
  1097. mactcp_wrapup()
  1098. {
  1099.     int theflag = emdp->closeflag;
  1100.     
  1101.     emdp->closeflag = 0;
  1102.     term_report(theflag);
  1103.     if (emdp->mtcpconnopen) {
  1104.         mactcp_close();
  1105.         emdp->closeflag = 0;        /* could get reset by MacTCP during close? */
  1106.     }
  1107.     mtreset();
  1108.     cls_usr();            /* WARNING: twp may disappear, emdp may change! */
  1109. }
  1110.  
  1111.  
  1112. /* reset the MacTCP session variables */
  1113.  
  1114. mtreset()
  1115. {
  1116.     emdp->fillcount = 0;
  1117.     emdp->waitcount = 0;
  1118.     emdp->send_wait = FALSE;
  1119.     emdp->sendp = emdp->fillp = emdp->sendbuf;
  1120.     
  1121.     emdp->closeflag = FALSE;
  1122.  
  1123.     /* no timers allocated for MacTCP */
  1124. }
  1125.  
  1126.  
  1127. #ifndef DUALTCP
  1128.  
  1129. char * strend(sptr)
  1130. register char * sptr;
  1131. {
  1132.     while (*sptr++) {
  1133.         ;
  1134.     }
  1135.     return(--sptr);
  1136. }
  1137.  
  1138. #endif
  1139.  
  1140. /* 
  1141.     Display some tcp statistics and a few lines of unacked data. Should be
  1142.     revised and integrated in with the normal logging system. 
  1143. */
  1144. /* this is now mac-dependent */
  1145.  
  1146. #define CLOSED         0
  1147. #define SYNRCVD         4
  1148. #define SYNSENT         6
  1149. #define ESTAB         8
  1150. #define FINWAIT1    10
  1151. #define FINWAIT2    12
  1152. #define CLOSEWAIT    14
  1153. #define CLOSING        16
  1154. #define LASTACK        18
  1155. #define TIMEWAIT    20
  1156.  
  1157. mactcp_status() 
  1158. {
  1159.     char dumpbuf[4000];
  1160.     char * dumpp;
  1161.     extern char * strend();
  1162.     TCPiopb infoblk;
  1163.     OSErr errcode;
  1164.     struct TCPConnectionStats *statp;
  1165.  
  1166.     memzero(&infoblk, sizeof(struct TCPiopb));    
  1167.  
  1168.     infoblk.ioCRefNum = ipp_refnum;
  1169.     infoblk.csCode = TCPGlobalInfo;
  1170.  
  1171.     /* used primarily for debugging purposes */
  1172.     if (errcode = PBControl(&infoblk, (Boolean) FALSE)) {
  1173.         ;
  1174.     }
  1175.  
  1176.     statblk.ioCRefNum = ipp_refnum;
  1177.     statblk.csCode = TCPStatus;
  1178.     statblk.tcpStream = keydp->tcp_stream;
  1179.  
  1180.     if (errcode = PBControl(&statblk, (Boolean) FALSE)) {
  1181.         /* 
  1182.             getcontext(keydp);    
  1183.             tcp_err(errcode);
  1184.                             tcp_err() uses emdp
  1185.             return(0);
  1186.             
  1187.             instead, fall through and show last stat block gathered...
  1188.         */
  1189.         /* statblk.csParam.status.connectionState = CLOSED;    fix stat report */
  1190.             /* no connection exists returns failure; TODO should cache closing stats? */
  1191.             return(0);
  1192.     }
  1193.     statp = statblk.csParam.status.connStatPtr;
  1194.     
  1195.     /* we hope dumpbuf does not get overwritten; this program protected by prayer
  1196.     "I shot a pointer into the buffer, I hope the program does not suffer ..." */
  1197.  
  1198.     dumpp = dumpbuf;
  1199.  
  1200.     sprintf(dumpbuf, "Connection State: ");
  1201.     dumpp = strend(dumpp);
  1202.         /* reposition pointer to end to add more */
  1203.     switch (statblk.csParam.status.connectionState)  {
  1204.         case CLOSED: {
  1205.             sprintf(dumpp, "Closed\r");
  1206.             break;
  1207.         }
  1208.         case SYNSENT: {
  1209.             sprintf(dumpp, "Trying to Open\r");
  1210.             break;
  1211.         }
  1212.         case SYNRCVD: {
  1213.             sprintf(dumpp, "SYNRCVD\r");
  1214.             break;
  1215.         }
  1216.         case ESTAB: {
  1217.             sprintf(dumpp, "Established\r");
  1218.             break;
  1219.         }
  1220.         case FINWAIT1: {
  1221.             sprintf(dumpp, "Closing (FIN-WAIT 1)\r");
  1222.             break;
  1223.         }
  1224.         case FINWAIT2: {
  1225.             sprintf(dumpp, "Closing (FIN-WAIT 2)\r");
  1226.             break;
  1227.         }
  1228.         case CLOSEWAIT: {
  1229.             sprintf(dumpp, "Closing (Close Wait)\r");
  1230.             break;
  1231.         }
  1232.         case CLOSING: {
  1233.             sprintf(dumpp, "Closing\r");
  1234.             break;
  1235.         }
  1236.         case LASTACK: {
  1237.             sprintf(dumpp, "Closing (Last Ack)\r");
  1238.             break;
  1239.         }
  1240.         case TIMEWAIT: {
  1241.             sprintf(dumpp, "Closing (Time Wait)\r");
  1242.             break;
  1243.         }
  1244.         default: {
  1245.             sprintf(dumpp, "Closing\r");
  1246.         }
  1247.     }
  1248.     dumpp = strend(dumpp);
  1249.     sprintf(dumpp, "\r");
  1250.     dumpp = strend(dumpp);
  1251.  
  1252.     sprintf(dumpp, "Packets sent: %5U  Resends: %5U\r", 
  1253.         statp->dataPktsSent, statp->dataPktsResent); 
  1254.         dumpp = strend(dumpp);
  1255.     sprintf(dumpp, "Packets rcvd: %5U\r",     
  1256.         statp->dataPktsRcvd); 
  1257.         /* Re-rcvd: %5U  Not for me: %5U */
  1258.         dumpp = strend(dumpp);
  1259. /*
  1260.     sprintf(dumpp, "Bad checksum: %5u  No data: %5u  Out of seq: %5u -- %u used\r", 
  1261.         tcpbadck, tcpnodata, tcpoutseq, tcpsoutseq); 
  1262.         dumpp = strend(dumpp);
  1263. */
  1264.     sprintf(dumpp, "Local Window: %5u  HostWindow: %5u\r", 
  1265.         statblk.csParam.status.rcvWindow, statblk.csParam.status.sendWindow); 
  1266.         dumpp = strend(dumpp);
  1267.     sprintf(dumpp, "         ACK: %08X   SEQ: %08X\r", 
  1268.         statblk.csParam.status.rcvNext, statblk.csParam.status.sendNext); 
  1269.         dumpp = strend(dumpp);
  1270.     sprintf(dumpp, "  Bytes Sent: %10U -- %u unacked\r",
  1271.         statp->bytesSent, emdp->fillcount - emdp->waitcount); 
  1272.         dumpp = strend(dumpp);
  1273.     sprintf(dumpp, "  Bytes Rcvd: %10U\r", 
  1274.         statp->bytesRcvd); 
  1275.         dumpp = strend(dumpp);
  1276.  
  1277.     fillwindow(TEXTOTHER, dumpbuf, (long) (dumpp - dumpbuf), monaco, 9, 0L);
  1278.         /* TEXT types have 4 bytes of length in them */
  1279. }
  1280.  
  1281.  
  1282. /* free the memory associated with a MacTCP session */
  1283.  
  1284. tcpmemoryreclaim(twp)
  1285. struct winds * twp;
  1286. {
  1287.     short cnt;
  1288.  
  1289.     if (twp->mtstream)
  1290.         free(twp->mtstream);
  1291.     if (twp->rcvbuf)
  1292.         free(twp->rcvbuf);
  1293.     if (twp->sendbuf)
  1294.         free(twp->sendbuf);
  1295.     if (twp->tcp_conn)
  1296.         free(twp->tcp_conn);
  1297.  
  1298.     twp->mtstream = NULL;
  1299.     twp->rcvbuf = NULL;
  1300.     twp->sendbuf = NULL;
  1301.     twp->tcp_conn = NULL;
  1302. }
  1303.  
  1304. #ifdef NOTMERGED
  1305. /* send MacTCP data waiting to be sent ... */
  1306.  
  1307. tcp_service()
  1308. {
  1309.     struct winds ** conp = conns;
  1310.     struct winds * conend = &conp[conncount];
  1311.     register struct winds * twp;
  1312.     
  1313.     while (conp < conend) {
  1314.         twp = *conp++;
  1315.                 
  1316.         if (twp->conntype != CONN_MACTCP)
  1317.             continue;
  1318.             
  1319.         if (twp->closeflag) {
  1320.             getcontext(twp);
  1321.             mactcp_wrapup();            /* WARNING: twp may disappear, emdp may change! */
  1322.         }
  1323.         if (twp->send_wait) {
  1324.             /* a packet is waiting for buffer; try to send again */
  1325.             getcontext(twp);
  1326.             mactcp_ex();
  1327.         }
  1328.         else if (twp->fillcount && (twp->fillcount == twp->waitcount)) {
  1329.             /* SHOULD NEVER REACH THIS POINT! once was a symptom of 
  1330.                 MacTCP async "let's waste some variables" behavior */
  1331.             getcontext(twp);
  1332.             mactcp_ex();
  1333.         }
  1334.     }
  1335. }
  1336.  
  1337. #endif
  1338.  
  1339.  
  1340. memzero(zptr, length)
  1341. register char * zptr;
  1342. int length;
  1343. {
  1344.     while (length--)
  1345.         *zptr++ = 0;
  1346. }
  1347.  
  1348.  
  1349. /* draw the packet counters */
  1350.  
  1351. tcp_drawcount(twp)
  1352. struct winds * twp;
  1353. {
  1354.     OSErr errcode;
  1355.     struct TCPConnectionStats *statp;
  1356.  
  1357.     if (!twp->connopen)
  1358.         return(0);
  1359.         
  1360.     statblk.ioCRefNum = ipp_refnum;
  1361.     statblk.csCode = TCPStatus;
  1362.     statblk.tcpStream = twp->tcp_stream;
  1363.  
  1364.     if (errcode = PBControl(&statblk, (Boolean) FALSE)) {
  1365.         return(0);
  1366.     }
  1367.     statp = statblk.csParam.status.connStatPtr;
  1368.     
  1369.     if (twp->in_cnt != statp->dataPktsRcvd) {
  1370.         twp->in_cnt = statp->dataPktsRcvd;
  1371.         getcontext(twp);
  1372.         drawincount();
  1373.     }
  1374.     if (twp->out_cnt != (statp->dataPktsSent + statp->dataPktsResent)) {
  1375.         twp->out_cnt = (statp->dataPktsSent + statp->dataPktsResent);
  1376.         getcontext(twp);
  1377.         if (twp->resends != statp->dataPktsResent) {
  1378.             twp->resends = statp->dataPktsResent;
  1379.             /* if (statblk.csParam.status.amtUnackedData != 0)
  1380.                 skip this test so even synced senders can note the acklessness... */
  1381.             twp->resending = TRUE;
  1382.         }
  1383.         drawoutcount();
  1384.     }
  1385.     else {
  1386.         if (twp->resending) {
  1387.             if (statblk.csParam.status.amtUnackedData == 0) {
  1388.                 twp->resending = FALSE;
  1389.                 getcontext(twp);
  1390.                 drawoutcount();
  1391.             }
  1392.         }
  1393.     }
  1394. }
  1395.     
  1396. mtcpurgent()
  1397. {    
  1398.     mactcpurgent = TRUE;
  1399. }
  1400.  
  1401.  
  1402.  
  1403. mtcpclrurgent()
  1404. {    
  1405.     mactcpurgent = 0;
  1406. }
  1407.  
  1408.  
  1409. beartrap()
  1410. {
  1411.     SysBeep(5);
  1412. }
  1413.  
  1414.